package service

import (
	"context"
	"os"
	"path"

	"gitee.com/linxing_3/sr-core/yerr"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/acl"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/conf"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/entity"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/repo"
)

func NewDomainGen(domainRepo *repo.DomainGen, tableRepo *repo.ModuleTable) *DomainGen {
	return &DomainGen{domainRepo: domainRepo, tableRepo: tableRepo}
}

type DomainGen struct {
	domainRepo *repo.DomainGen
	tableRepo  *repo.ModuleTable
}

func (d *DomainGen) GenDomain(ctx context.Context, req *acl.DomainGenReq) error {
	table := &entity.ModuleTable{
		Domain:  req.Domain,
		Comment: req.Description,
	}

	arg, err := d.tableRepo.ConvertTableToTplArg(table)
	if err != nil {
		return err
	}

	fileMap, err := d.getDomainOutFileMap(arg)
	if err != nil {
		return err
	}

	if !req.Force {
		for file := range fileMap {
			if f, err := os.Stat(file); err == nil && !f.IsDir() {
				return yerr.ErrDataExists.Errorf("%s file exists", file)
			}
		}
	}

	for file, content := range fileMap {
		if err := os.MkdirAll(path.Dir(file), os.ModePerm); err != nil {
			return err
		}

		if err := os.WriteFile(file, []byte(content), os.ModePerm); err != nil {
			return err
		}
	}

	return nil
}

func (d *DomainGen) getDomainOutFileMap(tplArg *acl.TplTable) (map[string]string, error) {
	outputFiles := map[string]string{}
	backProjPath := conf.Config.Devtools.BackProjPath

	d.domainRepo.WithTplDir(conf.Config.Devtools.TemplateDir)
	domainRootPath := path.Join(backProjPath, "apps", tplArg.DomainLower)

	var err error

	cmdPath := path.Join(backProjPath, "cmd", "domain")
	// cmd/domain/{domain}.g.go
	if outputFiles[cmdPath+tplArg.DomainLower+".g.go"], err = d.domainRepo.ExecuteCmdDomain(tplArg); err != nil {
		return nil, err
	}

	// app/{domian}/{domain}.go
	if outputFiles[path.Join(domainRootPath, tplArg.DomainLower+".g.go")], err = d.domainRepo.ExecuteBackDomain(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/conf/conf.go
	if outputFiles[path.Join(domainRootPath, "conf/conf.go")], err = d.domainRepo.ExecuteBackDomainConf(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/entity/migrate.go
	if outputFiles[path.Join(domainRootPath, "entity/migrate.go")], err = d.domainRepo.ExecuteBackDomainEntity(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/repo/provider.go
	if outputFiles[path.Join(domainRootPath, "repo/provider.go")], err = d.domainRepo.ExecuteBackDomainRepoProvider(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/server/provider.go
	if outputFiles[path.Join(domainRootPath, "service/provider.go")], err = d.domainRepo.ExecuteBackDomainServiceProvider(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/adapter/http/server.go
	if outputFiles[path.Join(domainRootPath, "adapter/http/server.go")], err = d.domainRepo.ExecuteBackDomainHttp(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/adapter/http/wire/api.go
	if outputFiles[path.Join(domainRootPath, "adapter/http/wire/api.go")], err = d.domainRepo.ExecuteBackDomainHttpWire(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/adapter/http/router/router.go
	if outputFiles[path.Join(domainRootPath, "adapter/http/router/router.go")], err = d.domainRepo.ExecuteBackDomainHttpRouter(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/adapter/http/api/provider.go
	if outputFiles[path.Join(domainRootPath, "adapter/http/api/provider.go")], err = d.domainRepo.ExecuteBackDomainApiProvider(tplArg); err != nil {
		return nil, err
	}

	// app/{domain}/adapter/http/api/api.go
	if outputFiles[path.Join(domainRootPath, "adapter/http/api/api.go")], err = d.domainRepo.ExecuteBackDomainHttpApi(tplArg); err != nil {
		return nil, err
	}

	return outputFiles, nil
}
